package com.youngjun.gateway.service.impl;

import com.alibaba.fastjson.JSON;
import com.youngjun.gateway.service.RouteDefinitionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @author virgojun
 */
@Service
public class RedisRouteDefinitionServiceImpl implements RouteDefinitionService {

    public static final String  GATEWAY_ROUTES = "gateway:routes";

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(findRouteDefinitions());
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return route
            .flatMap(routeDefinition -> {
                redisTemplate.opsForHash().put(GATEWAY_ROUTES, routeDefinition.getId(),
                        JSON.toJSONString(routeDefinition));
                return Mono.empty();
        });
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return routeId.flatMap(id -> {
            if (redisTemplate.opsForHash().hasKey(GATEWAY_ROUTES, id)) {
                redisTemplate.opsForHash().delete(GATEWAY_ROUTES, id);
                return Mono.empty();
            }
            return Mono.defer(() -> Mono.error(new NotFoundException("路由文件没有找到: " + routeId)));
        });
    }


    @Override
    public List<RouteDefinition> findRouteDefinitions() {
        return redisTemplate.opsForHash()
                .values(GATEWAY_ROUTES)
                .stream()
                .map(routeDefinition -> JSON.parseObject(routeDefinition.toString(), RouteDefinition.class))
                .collect(Collectors.toList());
    }
}
